package com.jxkj.mianshi.zytwo.juc;

import java.util.concurrent.TimeUnit;

/**
 * 功能描述：
 * 1. 保证线程之间的可见性
 *  1.1 int number = 0 前面如果不加volatile则其他线程会一直等待
 *
 * 2. 不保证原子性
 *  2.1 概念：不可分割，完整性。也既线程在做某个业务的时候，中间不可以被加塞或者分割，要么同时成功，要么同时失败
 *  2.2 其底层操作其实是分成很多指令的，一个n++操作会执行跟多条汇编命令
 *
 * @author wcx
 * @version 1.0
 */
public class MyData {

    /**
     * 1. 保证线程之间的可见性
     *  不加上 volatile 其他线程是不知道该线程进行了修改，所以就会一直在那等待
     */
    volatile int number = 0;

    public void addTo60() {
        this.number = 60;
    }

    /**
     * 加了volatile，但是并不会保证原子性
     */
    public synchronized void addPlus() {
        number++;
    }
}

class VolatileTest {
    public static void main(String[] args) {

        // getVolatileVisible();

        MyData myData = new MyData();
        // 20个线程进行计算
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.addPlus();
                }
            }, String.valueOf(i)).start();
        }

        // 需要看上面20个线程全部计算完，再看下main线程最终的结果只是多少
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }

        // 最后的结果不会20000
        System.out.println(Thread.currentThread().getName() + "main wait.."  +  myData.number);
    }

    /**
     * 1. volatile 的可见性
     */
    private static void getVolatileVisible() {
        MyData myData = new MyData();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + myData.number + "come in");
            try {
                TimeUnit.SECONDS.sleep(3);
                myData.addTo60();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + myData.number + "updated number");
        }, "AAA").start();

        while (myData.number == 0) {
            // 等待
        }
    }
}
